package org.jeecg.modules.jx.aspect;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.CodeSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;

@Aspect
@Component
@Slf4j
public class WebLogAspect {

    @Pointcut("execution(* org.jeecg.modules.miniAppCustomerEndPoint.controller..*.*(..))")
    public void miniAppControllerPointCut() {}

    @Pointcut("execution(* org.jeecg.modules.platformMasterEndPoint.controller..*.*(..))")
    public void platformControllerPointCut() {}

    @Around("miniAppControllerPointCut()")
    public Object doLogAroundMiniAppController(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Object result = httpRequestResponseLog(proceedingJoinPoint);
        return result;
    }

    @Around("platformControllerPointCut()")
    public Object doLogAroundPlatformController(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Object result = httpRequestResponseLog(proceedingJoinPoint);
        return result;
    }

    private Object httpRequestResponseLog(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        String requestId = UUID.randomUUID().toString();
        long startTime = System.currentTimeMillis();
        ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        // 打印请求相关参数
        log.info("{} ----------------- Start ---------------", requestId);
        // 打印请求 url
        log.info("URL            : {}", request.getRequestURL().toString());
        // 打印 Http method
        log.info("HTTP Method    : {}", request.getMethod());
        // 打印调用 controller 的全路径以及执行方法
        log.info("Class Method   : {}.{}", proceedingJoinPoint.getSignature().getDeclaringTypeName(), proceedingJoinPoint.getSignature().getName());
        // 打印请求的 IP
        log.info("IP             : {}", request.getRemoteAddr());
        // 打印请求url参数
        log.info("Query String   : {}", request.getQueryString());
        // 打印请求体
//        BufferedReader bufferedReader = request.getReader();
//        String requestBody = "";
//        String line = null;
//        while ((line = bufferedReader.readLine()) != null) {
//            requestBody += line;
//        }
//        log.info("Request Body   : {}", requestBody);
//        log.info("Request Args   : {}", proceedingJoinPoint.getArgs());
//        String requestBody = parseRequestBodyServletRequest(proceedingJoinPoint);
//        log.info("Request Args   : {}", requestBody);


        Object result = proceedingJoinPoint.proceed();

        // 打印出参
        log.info("Response Args  : {}", JSONObject.toJSONString(result));
        // 执行耗时
        log.info("Time-Consuming : {} ms", System.currentTimeMillis() - startTime);
        log.info("{} ----------------- end ---------------", requestId);

        return result;
    }


    /**
     * It is illegal to call this method if the current request is not in asynchronous mode (i.e. isAsyncStarted() returns false)
     * java.lang.IllegalStateException: It is illegal to call this method if the current request is not in asynchronous mode (i.e. isAsyncStarted() returns false)
     * java.lang.IllegalStateException: It is illegal to call this method if the current request is not in asynchronous mode (i.e. isAsyncStarted() returns false)
     * @param proceedingJoinPoint
     * @return
     */
    private String parseRequestBodyServletRequest(ProceedingJoinPoint proceedingJoinPoint) {
        Object[] parameterValues = proceedingJoinPoint.getArgs();
        if (parameterValues.length == 0) {
            log.info("无request body");
            return "";
        }
        Signature signature = proceedingJoinPoint.getSignature();
        if (Objects.isNull(signature)) {
            return "";
        }

        String[] parameterNames = ((CodeSignature)signature).getParameterNames();
        if (Objects.isNull(parameterNames) || parameterNames.length != parameterValues.length) {
            return "";
        }

        Map<String, Object> params = new HashMap<>();
        for (int i = 0 ; i < parameterNames.length; i ++) {
            params.put(parameterNames[i], parameterValues[i]);
        }

        return JSON.toJSONString(params, SerializerFeature.WriteMapNullValue);
    }
}
